Degrading
Gracefully in the Absence of an Interface
Because a control
may not support any interface other than IUnknown, a container has to
degrade gracefully when it encounters the absence of any particular interface.
One might
question the usefulness of a control with nothing more than IUnknown.
But consider the advantages that a control receives from a container s visual
programming environment (such as VB) when the container recognizes the object
as a control:
1. A button for the object appears in a toolbox.
2. One can create an object by dragging it from
the toolbox onto a form.
3. One can give the object a name that is
recognized in the visual programming environment.
4. The same name in (3) above can be used
immediately in writing any other code for controls on the same form (or even a
different form).
5. The container can automatically provide code
entry points for any events available from that object.
6. The container provides its own property
browsing UI for any available properties.
When an
object isn t recognized as a control, then it potentially loses all of these
very powerful and beneficial integration features. For example, in Visual Basic
4.0 it is very difficult to really integrate some random object that is not a
control in the complete sense, but may still have properties and events.
Because VB 4 s idea of a control is very restrictive the object does not gain
any of the integration features above. But even a control with IUnknown,
where the mere lifetime of the control determines the existence of some
resource, should be able to gain the integration capabilities described above.
As current
tools require a large set of control interfaces to gain any advantage, controls
are generally led to over-implementation, such that they contain more code than
they really need. Controls that could be 7K might end up being 25K, which is a
big performance problem in areas such as the Internet. This has also led to the
perception that one can only implement a control with one tool like the CDK
because of the complexity of implementing all the interfaces and this has implications when a large DLL like
OC30.DLL is required for such a control, increasing the working set. If not all
interfaces are required, then this opens up many developers to writing very
small and light controls with straight OLE or with other tools as well,
minimizing the overhead for each control.
This is why
this appendix recognizes a control as any object with a CLSID and an IUnknown
interface. Even with nothing more than IUnknown, a container with a programming
environment should be able to provide at least features #3 and #4 from the list
above. If the object provides a ToolBoxBitmap32 registry entry, it gains #1 and
#2. If the object supplies IConnectionPointContainer (and IProvideClassInfo
generally) for some event set, it gains #5, and if it supports IDispatch
for properties and methods, it gains #6, as well as better code integration in
the container.
In short, an
object should be able to implement as little as IDispatch and one event
set exposed through IConnectionPointContainer to gain all of those
visual features above.
With this in
mind, the following table describes what a container might do in the absence of
any possible interface. Note that only those interfaces are listed that the
container will directly obtain through QueryInterface. Other interfaces,
like IOleInPlaceActiveObject, are obtained through other means.
Interface |
Meaning
of Interface Absence |
IViewObject2 |
The control
has no visuals that it will draw itself, so has no definite extents to
provide. In run-time, the container simply doesn t attempt to draw anything
when this interface is absent. In design time, the container must at least
draw some kind of default rectangle with a name in it for such a control, so
a user in a visual programming environment can select the object and check
out its properties, methods, and events that exist. Handling the absence of IViewObject2
is critical for good visual programming support. |
IOleObject |
The control
doesn t need the site whatsoever, nor does it take part in any embedded
object layout negotiation. Any information (like control extents) that a
container might expect from this interface should be filled in with
container-provided defaults. |
IOleInPlaceObject |
The control
doesn t go in-place active (like a label) and thus never attempts to activate
in this manner. Its only activation may be its property pages. |
IOleControl |
Control has
no mnemonics and no use of ambient properties, and doesn t care if the
container ignores events. In the absence of this interface, the container
just doesn t call its methods. |
IDataObject |
The control
provides no property sets nor any visual renderings that could be cached, so
the container would choose to cache some default presentation in the absence
of this interface (support for CF_METAFILEPICT, specifically) and disable any
property-set related functionality. |
IDispatch |
The control
has no custom properties or methods. The container does not need to try to
show any control properties in this case, and should disallow any custom
method calls that the container doesn t recognize as belonging to its own
extended controls (that may support methods and properties). As extended
controls generally delegate certain IDispatch calls to the control, an
extended control should not expect the control to have IDispatch at all. |
IConnectionPointContainer |
The control
has no events, so the container doesn t have to think about handling any. |
IProvideClassInfo[2] |
The control
either doesn t have type information or events, or the container needs to go
into the control s type information through the control s registry entries.
The existence of this interface is an optimization. |
ISpecifyPropertyPages |
The control
has no property pages, so if the container has any UI that would invoke them,
the container should disable that UI. |
IPerPropertyBrowsing |
The control
has no display name itself, no predetermined strings and values, and no
property to page mapping. This interface is nearly always used for generating
container user interface, so such UI elements would be disabled in the absence
of this interface. |
IPersist* |
The control
has no persistent state to speak of, so the container doesn t have to worry
about saving any control-specific data. The container will, of course, save
its own information about the control in its own form or document, but the
control itself has nothing to contribute to that information. |
IOleCache[2] |
The object
doesn t support caching. A container can still support caching by just
creating a data cache itself using CreateDataCache. |